Structuring and constructing modules part 4: Accessing modules in any depths

One of the good parts about module systems in modular programming, which applied by {box} package fortunately, is they allow deep nested scripts / folders in any depth as modules, then import these modules with deep nesting. On the previous section in Chapter 3, we talk about statistics/ subfolder, in which this folder is 1 level deep from the ./module. {box} doesn’t limit you to just 1 level of nesting only. You can organize your code into multiple layers of directories, creating a hierarchical structure that makes sense for your project’s complexity and organization needs.


Multi-level folder structures

From the previous ./module, let’s spice it up a bit by updating (or just get the source code of ./module in GitHub) matrix_ops.r to store functions that rewrites * for matrix multiplication and overrides ^ where a specific value, ^-1, implies the inverse of the matrix, and tables.r to store functions for displaying tables in R, and extending the ./module/statistics subfolder by adding another level of organization, e.g. you want to add statistical model utilities organized by model type, saved them in R scripts under ./module/statistics/models subfolder.

module/
├── __init__.r
├── convert.r
├── hello_world.r
├── matrix_ops.r              # <------------- Under root `./module` folder
├── not_func.r
├── tables.r                  # <------------- Under root `./module` folder
└── statistics/
    ├── __init__.r
    ├── cor.r
    ├── corrr.r
    ├── time_series.r
    └── models/               # <------------- Subfolder within subfolder
        ├── __init__.r
        ├── linear.r
        ├── logistic.r
        └── baseline_logit.r

In this structure, ./module/statistics/models is nested two (2) levels deep from the root ./module folder. Each directory still requires its own __init__.r file to be recognized as a module.

WarningAbout __init__.r

Just don’t forget that every folder you want to treat as a module must contain an __init__.r file, regardless of its depth in the folder hierarchy.

Under ./module/statistics/models subfolder, place this in __init__.r file:

#' @export
box::use(
    ./linear,
    ./logistic,
    ./baseline_logit
)

And since we are adding another module within ./module/statistics, update its __init__.r initialization file:

#' @export
box::use(
    ./cor,
    ./corrr,
    ./time_series, 
    ./models             # The new export for `statistics` module
)

Accessing deeply nested modules

You can import these deeply nested modules using the same syntax patterns you’ve already learned in the previous chapter, just with longer paths:

box::use(
    ./module/statistics/time_series
)

time_series$ACF(AirPassengers)
 [1] 1.0000000 0.9480473 0.8755748 0.8066812 0.7526254 0.7137700 0.6817336
 [8] 0.6629044 0.6556105 0.6709483 0.7027199

Or you can use the parent module and traverse through the hierarchy:

box::use(
    md = ./module
)

# Navigate through the nested structure
md$statistics$time_series$ACF(AirPassengers)
 [1] 1.0000000 0.9480473 0.8755748 0.8066812 0.7526254 0.7137700 0.6817336
 [8] 0.6629044 0.6556105 0.6709483 0.7027199
TipSource code

The code for some script is too long. Navigate the source code by clicking each hyperlinked text:

  1. Under ./module:

  2. Under ./module/statistics/models: